package com.decelo.jpa.shiro;

import com.decelo.jpa.entity.sys.Menu;
import com.decelo.jpa.entity.sys.Role;
import com.decelo.jpa.entity.sys.User;
import com.decelo.jpa.entity.sys.jwt;
import com.decelo.jpa.redis.JWTRedisDAO;
import com.decelo.jpa.result.UserToken;
import com.decelo.jpa.service.UserService;
import com.decelo.jpa.utils.JWTUtil;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class MyRealm extends AuthorizingRealm {

    private static final Logger logger = LogManager.getLogger(MyRealm.class);
    @Autowired
    private UserService userService;
    @Autowired
    private JWTRedisDAO jwtRedisDAO;

    /**
     * 必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof jwt;
    }

    /**
     * 重写权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String principal=(String)principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo authenticationInfo = new SimpleAuthorizationInfo();

        //获取当前token的username
        //String username = (String)JWTUtil.getClaims(UserToken.Salt, principal).get("username");
        User user = userService.getUserByName(principal);
        //获取当前对象的下的role
        //Set<String> rolestr=new HashSet<>();
       //List<Role> roles=new ArrayList<>();
        for (Role role:user.getRoles()){
            authenticationInfo.addRole(role.getrCode());
            //rolestr.add(role.getrCode());
            for(Menu m:role.getMenus()){
                //System.out.println(p);
                authenticationInfo.addStringPermission(m.getPermissionKeyValue());
            }
        }
        //设入当前角色
        //authenticationInfo.addRoles(rolestr);
        //authenticationInfo.setRoles(rolestr);
        //设入permission [user:add]
        //authenticationInfo.setStringPermissions(userService.queryResourcesByName(principal));
        //authenticationInfo.setStringPermissions(userService.findMenukeyByName(principal));
        return authenticationInfo;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String principals = (String)authenticationToken.getPrincipal();
        String username = principals.split(":")[0];
        String token=principals.split(":")[1];
        if (username == null) {
            throw new AuthenticationException("token invalid");
        }
        User user = userService.getUserByName(username);
        //加入redis定时检查token是否过期
        String redistoken = jwtRedisDAO.get(UserToken.admin + "token");
        if (!redistoken.equals(token)){
            throw new AuthenticationException("TOKEN 过期,请重新登陆！");
        }
        if (user == null) {
            throw new AuthenticationException("User didn't existed!");
        }
        if (!token.equals(user.getJwttoken())){
            throw new AuthenticationException("Username or password error");
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                //用户名
                username,
                //account+salt
                user.getAuthenticator(),
                //salt
                ByteSource.Util.bytes(user.getSalt()),
                //realm name
                getName()
        );

        return authenticationInfo;
        //new SimpleAuthenticationInfo(token, token, "my_realm");
    }
}
